From a96be4d78bfb8b44e4aac99ba2f65099cf403482 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C3=98yvind=20Kol=C3=A5s?= Date: Mon, 26 Sep 2005 22:06:32 +0000 Subject: [PATCH] upgrading BablFishPath --- ChangeLog | 23 +++ babl/babl-conversion.c | 96 +++++++----- babl/babl-core.c | 5 + babl/babl-fish-path.c | 307 +++++++++++++++++++++++-------------- babl/babl-fish-reference.c | 4 +- babl/babl-fish-simple.c | 3 + babl/babl-ids.h | 24 ++- babl/babl-introspect.c | 4 +- babl/babl-model.c | 29 ++-- babl/babl.c | 2 - 10 files changed, 320 insertions(+), 177 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4b4fcbe..8385846 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2005-09-27 Øyvind Kolås + + Upgrade of BablFishPath. + + * babl/babl-fish-path.c: (legal_error), (max_path_length), + (get_conversion_chain), (chain_contains_fmt), (chain_gen_each), + (babl_fish_path), (chain_process), (babl_fish_path_process), + (test_create), (chain_error): Various updates, needed instrumentation + and error data is now calculated and cached. + * babl/babl-fish-reference.c: (babl_fish_reference): do not update + instrumentation for internal calls. + * babl/babl-fish-simple.c: (babl_fish_simple): do not update + instrumentation for internal calls. + * babl/babl-introspect.c: (conversion_introspect): some more + information. + * babl/babl-model.c: (test_create), (babl_model_is_symmetric): use + comparion function from babl-util + * babl/babl-conversion.c: (test_create), (babl_conversion_cost), + (babl_conversion_error): use comparion function from babl-util. + * babl/babl.c: (babl_init): no need to do post extension tricks + anymore. + * babl/babl-core.c: (babl_core_init): added PAD component. + 2005-09-27 Øyvind Kolås * babl/babl-util.h, diff --git a/babl/babl-conversion.c b/babl/babl-conversion.c index 593110c..53721d5 100644 --- a/babl/babl-conversion.c +++ b/babl/babl-conversion.c @@ -402,7 +402,7 @@ babl_conversion_process (Babl *babl, return n; } -#define pixels 8192*2 +#define test_pixels 512 static double * test_create (void) @@ -412,21 +412,37 @@ test_create (void) srandom (20050728); - test = babl_malloc (sizeof (double) * pixels * 4); + test = babl_malloc (sizeof (double) * test_pixels * 4); - for (i = 0; i < pixels * 4; i++) + for (i = 0; i < test_pixels * 4; i++) test [i] = (double) random () / RAND_MAX; - return test; } +long +babl_conversion_cost (BablConversion *conversion) +{ + if (!conversion) + return 100000000.0; + if (conversion->error==-1.0) + babl_conversion_error (conversion); + return conversion->cost; +} + double babl_conversion_error (BablConversion *conversion) { Babl *fmt_source; Babl *fmt_destination; - Babl *fmt_rgba_double; + Babl *fmt_rgba_double = fmt_rgba_double = babl_format_new ( + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); double error = 0.0; unsigned int ticks_start = 0; @@ -439,6 +455,9 @@ babl_conversion_error (BablConversion *conversion) void *ref_destination; double *ref_destination_rgba_double; + Babl *fish_rgba_to_source; + Babl *fish_reference; + Babl *fish_destination_to_rgba; if (!conversion) return 0.0; @@ -446,13 +465,17 @@ babl_conversion_error (BablConversion *conversion) fmt_source = BABL(conversion->source); fmt_destination = BABL(conversion->destination); + fish_rgba_to_source = babl_fish_reference (fmt_rgba_double, fmt_source); + fish_reference = babl_fish_reference (fmt_source, fmt_destination); + fish_destination_to_rgba = babl_fish_reference (fmt_destination, fmt_rgba_double); + if (fmt_source == fmt_destination) { conversion->error = 0.0; return 0.0; } - if (!(fmt_source->instance.id != BABL_RGBA && + if (!(fmt_source->instance.id != BABL_RGBA && fmt_destination->instance.id != BABL_RGBA && fmt_source->instance.id != BABL_DOUBLE && fmt_destination->instance.id != BABL_DOUBLE && @@ -468,51 +491,41 @@ babl_conversion_error (BablConversion *conversion) test=test_create (); - fmt_rgba_double = babl_format_new ( - babl_model ("RGBA"), - babl_type ("double"), - babl_component ("R"), - babl_component ("G"), - babl_component ("B"), - babl_component ("A"), - NULL); - - source = babl_calloc (pixels, fmt_source->format.bytes_per_pixel); - destination = babl_calloc (pixels, fmt_destination->format.bytes_per_pixel); - ref_destination = babl_calloc (pixels, fmt_destination->format.bytes_per_pixel); - destination_rgba_double = babl_calloc (pixels, fmt_rgba_double->format.bytes_per_pixel); - ref_destination_rgba_double = babl_calloc (pixels, fmt_rgba_double->format.bytes_per_pixel); + source = babl_calloc (test_pixels, fmt_source->format.bytes_per_pixel); + destination = babl_calloc (test_pixels, fmt_destination->format.bytes_per_pixel); + ref_destination = babl_calloc (test_pixels, fmt_destination->format.bytes_per_pixel); + destination_rgba_double = babl_calloc (test_pixels, fmt_rgba_double->format.bytes_per_pixel); + ref_destination_rgba_double = babl_calloc (test_pixels, fmt_rgba_double->format.bytes_per_pixel); - babl_process (babl_fish_reference (fmt_rgba_double, fmt_source), - test, source, pixels); + babl_process (fish_rgba_to_source, + test, source, test_pixels); ticks_start = babl_ticks (); babl_process (babl_fish_simple (conversion), - source, destination, pixels); + source, destination, test_pixels); ticks_end = babl_ticks (); - babl_process (babl_fish_reference (fmt_source, fmt_destination), - source, ref_destination, pixels); + babl_process (fish_reference, + source, ref_destination, test_pixels); - babl_process (babl_fish_reference (fmt_destination, fmt_rgba_double), - ref_destination, ref_destination_rgba_double, pixels); - babl_process (babl_fish_reference (fmt_destination, fmt_rgba_double), - destination, destination_rgba_double, pixels); + babl_process (fish_destination_to_rgba, + ref_destination, ref_destination_rgba_double, test_pixels); + babl_process (fish_destination_to_rgba, + destination, destination_rgba_double, test_pixels); - { - int i; + error = babl_rel_avg_error (destination_rgba_double, + ref_destination_rgba_double, + test_pixels*4); + + fish_rgba_to_source->fish.processings--; + fish_reference->fish.processings--; + fish_destination_to_rgba->fish.processings-=2; + + fish_rgba_to_source->fish.pixels -= test_pixels; + fish_reference->fish.pixels -= test_pixels; + fish_destination_to_rgba->fish.pixels -= 2 * test_pixels; - for (i=0;i #include "babl-internal.h" -#define BABL_LEGAL_ERROR 0.000001 +static double +chain_error (Babl *fmt_source, + Babl *fmt_destination, + BablConversion **chain, + int conversions); + +//#define BABL_LEGAL_ERROR 0.000001 +//#define BABL_LEGAL_ERROR 0.01 + +static double legal_error (void) +{ + double error=0.00000001; + const char *env; + + env=getenv ("BABL_ERROR"); + if (env) + error = atof (env); + else if (error<=0.0) + error = 0.0; + return error; +} + +static int max_path_length (void) +{ + int max_length=3; + const char *env; + + env=getenv ("BABL_PATH_LENGTH"); + if (env) + max_length = atoi (env); + if (max_length>BABL_HARD_MAX_PATH_LENGTH) + max_length=BABL_HARD_MAX_PATH_LENGTH; + else if (max_length<=0) + max_length = 1; + return max_length; +} typedef struct BablChainContext { Babl *from; @@ -27,80 +63,32 @@ typedef struct BablChainContext { double *best_cost; double *best_loss; + double *best_error; - Babl **chain; + BablConversion **chain; int *conversions; - Babl **temp_chain; + BablConversion **temp_chain; int temp_conversions; int max_conversions; } BablChainContext; -static int -format_has_alpha (Babl *babl) -{ - int i; - for (i=0; iformat.components; i++) - if (babl->format.component[i]->instance.id == BABL_ALPHA) - return 1; - return 0; -} - -static int -format_analytic_loss (Babl *source, - Babl *destination) -{ - int loss = 0; - - if (source->format.components < - destination->format.components) - { - loss |= 8; - } - - if ( format_has_alpha (source) && - !format_has_alpha (destination)) - { - loss |= 4; - } - - if ( BABL(source->format.type[0])->type.bits > - BABL(destination->format.type[0])->type.bits) - { - loss |= 2; - } - - if ( source->format.bytes_per_pixel > - destination->format.bytes_per_pixel) - { - loss |= 1; - } - - - - - return loss; -} - - static int chain_gen_each (Babl *babl, void *userdata); static int -get_conversion_chain (Babl *from, - Babl *to, - - double *best_cost, - double *best_loss, - Babl **chain, - int *conversions, - - Babl **temp_chain, - int temp_conversions, - - int max_conversions) +get_conversion_chain (Babl *from, + Babl *to, + double *best_cost, + double *best_loss, + double *best_error, + BablConversion **chain, + int *conversions, + BablConversion **temp_chain, + int temp_conversions, + int max_conversions) { BablChainContext context; @@ -113,6 +101,7 @@ get_conversion_chain (Babl *from, *conversions = 0; *best_cost = 200000.0; *best_loss = 200000.0; + *best_error = 200000.0; chain[0] = NULL; temp_chain[0] = NULL; @@ -130,6 +119,7 @@ get_conversion_chain (Babl *from, context.best_cost = best_cost; context.best_loss = best_loss; + context.best_error = best_error; context.chain = chain; context.conversions = conversions; @@ -153,12 +143,12 @@ get_conversion_chain (Babl *from, else { if (BABL(temp_chain[temp_conversions-1]) && - BABL(temp_chain[temp_conversions-1]->conversion.destination)-> + BABL(temp_chain[temp_conversions-1]->destination)-> format.from) babl_list_each ( (void **) - BABL(temp_chain[temp_conversions-1]->conversion.destination)-> + BABL(temp_chain[temp_conversions-1]->destination)-> format.from, chain_gen_each, &context); @@ -167,6 +157,21 @@ get_conversion_chain (Babl *from, return 0; } +static int +chain_contains_fmt (BablConversion **chain, + int conversions, + Babl *fmt) +{ + int i; + for (i=0;idestination)==fmt || + BABL(chain[i]->source)==fmt) + { + return 1; + } + return 0; +} + static int chain_gen_each (Babl *babl, void *userdata) @@ -174,50 +179,44 @@ chain_gen_each (Babl *babl, BablChainContext *c = userdata; /* fill in the conversion for the chain index we are at */ - c->temp_chain[c->temp_conversions] = babl; + c->temp_chain[c->temp_conversions] = (BablConversion*)babl; { - if (BABL(babl->conversion.destination) == c->to) + if ((BABL(babl->conversion.destination) == c->to) ) { /* a candidate path has been found */ - double temp_cost = 0.0; - double temp_loss = 0.0; - double error = 1.0; - int analytic_loss = 0; + double temp_cost = 0.0; + double temp_error = 1.0; int i; for (i=0; i < c->temp_conversions+1; i++) { - error *= (1.0+c->temp_chain[i]->conversion.error); - temp_cost += c->temp_chain[i]->conversion.cost; - analytic_loss |= format_analytic_loss ( - BABL(c->temp_chain[i]->conversion.source), - BABL(c->temp_chain[i]->conversion.destination)); + temp_error *= (1.0+babl_conversion_error (c->temp_chain[i])); + temp_cost += babl_conversion_cost (c->temp_chain[i]); } - temp_loss = analytic_loss; - if (error <= (1.0 + BABL_LEGAL_ERROR) /* we're legal */ && - (temp_loss >= format_analytic_loss (c->from, c->to)) && - - - /* better than the existing best candidate */ - ( temp_loss < *c->best_loss || - (temp_loss == *c->best_loss && - temp_cost < *c->best_cost))) + if (temp_cost < *c->best_cost && + temp_error - 1.0 <= legal_error() && /* this check before the next; which does a more accurate + measurement of the error */ + (temp_error=chain_error (c->from, c->to, c->temp_chain, c->temp_conversions+1)) <= legal_error() + ) { int i; *c->best_cost = temp_cost; - *c->best_loss = temp_loss; + *c->best_error = temp_error; *c->conversions = c->temp_conversions + 1; /* copy from temp chain to best chain */ - for (i = 0.0; i < *c->conversions; i++) + for (i = 0; i < *c->conversions; i++) c->chain[i] = c->temp_chain[i]; } } - else + else if (babl->conversion.source != babl->conversion.destination && + !chain_contains_fmt (c->temp_chain, + c->temp_conversions, + BABL(babl->conversion.destination))) { /* try to add another conversion level in chain,.. */ get_conversion_chain (c->from, /* irrelevant when recalled */ @@ -225,6 +224,7 @@ chain_gen_each (Babl *babl, c->best_cost, c->best_loss, + c->best_error, c->chain, c->conversions, @@ -273,7 +273,7 @@ babl_fish_path (Babl *source, { Babl *babl = NULL; char *name = create_name (source, destination, 1); - Babl *temp_chain[BABL_MAX_PATH_LENGTH]; + BablConversion *temp_chain[BABL_HARD_MAX_PATH_LENGTH]; babl_assert (BABL_IS_BABL (source)); babl_assert (BABL_IS_BABL (destination)); @@ -292,6 +292,7 @@ babl_fish_path (Babl *source, babl->fish.processings = 0; babl->fish.pixels = 0; + babl->fish.error = 200000; babl->fish_path.cost = 200000; babl->fish_path.loss = 200000; @@ -305,11 +306,13 @@ babl_fish_path (Babl *source, destination, &babl->fish_path.cost, &babl->fish_path.loss, - (Babl**)(babl->fish_path.conversion), + &babl->fish.error, + (BablConversion**)(babl->fish_path.conversion), &babl->fish_path.conversions, temp_chain, 0, - BABL_MAX_PATH_LENGTH); + max_path_length ()); + if (babl->fish_path.conversions==0) { babl_free (babl); @@ -345,7 +348,7 @@ chain_process (BablConversion *chain[], for (i=0; ifish.source)->instance.name, - BABL(babl->fish.destination)->instance.name); - - for (i=0; i< babl->fish_path.conversions; i++) - babl_log ("\t%s\n", - BABL(babl->fish_path.conversion[i])->instance.name); -*/ return chain_process (babl->fish_path.conversion, babl->fish_path.conversions, @@ -420,3 +409,99 @@ babl_fish_path_process (Babl *babl, n); } + +#define test_pixels 128 + +static double * +test_create (void) +{ + double *test; + int i; + + srandom (20050728); + + test = babl_malloc (sizeof (double) * test_pixels * 4); + + for (i = 0; i < test_pixels * 4; i++) + test [i] = (double) random () / RAND_MAX; + + return test; +} + +static double +chain_error (Babl *fmt_source, + Babl *fmt_destination, + BablConversion **chain, + int conversions) +{ + Babl *fmt_rgba_double = babl_format_new ( + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + + double error = 0.0; + + double *test; + void *source; + void *destination; + double *destination_rgba_double; + void *ref_destination; + double *ref_destination_rgba_double; + + Babl *fish_rgba_to_source = babl_fish_reference (fmt_rgba_double, fmt_source); + Babl *fish_reference = babl_fish_reference (fmt_source, fmt_destination); + Babl *fish_destination_to_rgba = babl_fish_reference (fmt_destination, fmt_rgba_double); + + test=test_create (); + + + source = babl_calloc (test_pixels, fmt_source->format.bytes_per_pixel); + destination = babl_calloc (test_pixels, fmt_destination->format.bytes_per_pixel); + ref_destination = babl_calloc (test_pixels, fmt_destination->format.bytes_per_pixel); + destination_rgba_double = babl_calloc (test_pixels, fmt_rgba_double->format.bytes_per_pixel); + ref_destination_rgba_double = babl_calloc (test_pixels, fmt_rgba_double->format.bytes_per_pixel); + + /* create sourcebuffer from testbuffer in the correct format */ + babl_process (fish_rgba_to_source, + test, source, test_pixels); + + /* calculate the reference buffer of how it should be */ + babl_process (fish_reference, + source, ref_destination, test_pixels); + + /* calculate this chains view of what the result should be */ + chain_process (chain, conversions, source, destination, test_pixels); + + /* transform the reference and the actual destination buffers to RGBA + * for comparison with each other + */ + babl_process (fish_destination_to_rgba, + ref_destination, ref_destination_rgba_double, test_pixels); + babl_process (fish_destination_to_rgba, + destination, destination_rgba_double, test_pixels); + + error = babl_rel_avg_error (destination_rgba_double, + ref_destination_rgba_double, + test_pixels*4); + + fish_rgba_to_source->fish.processings--; + fish_reference->fish.processings--; + fish_destination_to_rgba->fish.processings-=2; + + fish_rgba_to_source->fish.pixels -= test_pixels; + fish_reference->fish.pixels -= test_pixels; + fish_destination_to_rgba->fish.pixels -= 2 * test_pixels; + + babl_free (source); + babl_free (destination); + babl_free (destination_rgba_double); + babl_free (ref_destination); + babl_free (ref_destination_rgba_double); + babl_free (test); + + return error; +} diff --git a/babl/babl-fish-reference.c b/babl/babl-fish-reference.c index 91acfbc..88119a2 100644 --- a/babl/babl-fish-reference.c +++ b/babl/babl-fish-reference.c @@ -69,7 +69,9 @@ babl_fish_reference (Babl *source, babl->fish.processings = 0; babl->fish.pixels = 0; - + babl->fish.error = 0.0; /* assuming the provided reference conversions for types + and models are as exact as possible + */ { Babl *ret = babl_db_insert (babl_fish_db (), babl); if (ret!=babl) diff --git a/babl/babl-fish-simple.c b/babl/babl-fish-simple.c index dc9d62e..6b0fd49 100644 --- a/babl/babl-fish-simple.c +++ b/babl/babl-fish-simple.c @@ -47,6 +47,9 @@ babl_fish_simple (BablConversion *conversion) babl->fish.processings = 0; babl->fish.pixels = 0; babl->fish_simple.conversion = conversion; + babl->fish.error = 0.0; /* babl fish simple should only be used by bablfish + reference, and babl fish reference only requests clean + conversions */ { Babl *ret = babl_db_insert (babl_fish_db (), babl); diff --git a/babl/babl-ids.h b/babl/babl-ids.h index 9b54642..27280fd 100644 --- a/babl/babl-ids.h +++ b/babl/babl-ids.h @@ -39,16 +39,18 @@ enum { BABL_TYPE_LAST_INTERNAL, BABL_MODEL_BASE = 1000, + BABL_GRAY, + BABL_GRAY_ALPHA, + BABL_GRAY_ALPHA_PREMULTIPLIED, BABL_RGB, BABL_RGBA, - BABL_RGB_GAMMA_2_2, - BABL_RGBA_GAMMA_2_2, BABL_RGBA_PREMULTIPLIED, - BABL_GRAY, - BABL_GRAY_ALPHA, BABL_GRAY_GAMMA_2_2, BABL_GRAY_GAMMA_2_2_ALPHA, - BABL_GRAY_ALPHA_PREMULTIPLIED, + BABL_GRAY_GAMMA_2_2_ALPHA_PREMULTIPLIED, + BABL_RGB_GAMMA_2_2, + BABL_RGBA_GAMMA_2_2, + BABL_RGBA_GAMMA_2_2_PREMULTIPLIED, BABL_YCBCR, BABL_YCBCR_ALPHA, BABL_CIE_LAB, @@ -56,6 +58,8 @@ enum { BABL_MODEL_LAST_INTERNAL, BABL_COMPONENT_BASE = 10000, + BABL_LUMINANCE, + BABL_LUMINANCE_MUL_ALPHA, BABL_RED, BABL_GREEN, BABL_BLUE, @@ -63,12 +67,16 @@ enum { BABL_RED_MUL_ALPHA, BABL_GREEN_MUL_ALPHA, BABL_BLUE_MUL_ALPHA, + BABL_LUMA, + BABL_LUMA_MUL_ALPHA, BABL_RED_GAMMA_2_2, BABL_GREEN_GAMMA_2_2, BABL_BLUE_GAMMA_2_2, - BABL_LUMINANCE, - BABL_LUMINANCE_GAMMA_2_2, - BABL_LUMINANCE_MUL_ALPHA, + BABL_RED_GAMMA_2_2_MUL_ALPHA, + BABL_GREEN_GAMMA_2_2_MUL_ALPHA, + BABL_BLUE_GAMMA_2_2_MUL_ALPHA, + + BABL_X, BABL_Y, BABL_Z, diff --git a/babl/babl-introspect.c b/babl/babl-introspect.c index ea6a4ec..e61b474 100644 --- a/babl/babl-introspect.c +++ b/babl/babl-introspect.c @@ -165,7 +165,9 @@ conversion_introspect (Babl *babl) { babl_log ("\t\tprocessings:%i pixels:%li", babl->conversion.processings, babl->conversion.pixels); - babl_log ("\t\tcost: %i error: %f", babl->conversion.cost, babl->conversion.error); + babl_log ("\t\tcost: %i error: %f", + babl_conversion_cost (&babl->conversion), + babl_conversion_error (&babl->conversion)); } static void diff --git a/babl/babl-model.c b/babl/babl-model.c index 6e5428d..c1f1bdb 100644 --- a/babl/babl-model.c +++ b/babl/babl-model.c @@ -173,7 +173,7 @@ babl_model_new (void *first_argument, #define TOLERANCE 0.001 -#define pixels 512 +#define test_pixels 512 static double * test_create (void) @@ -183,9 +183,9 @@ test_create (void) srandom (20050728); - test = babl_malloc (sizeof (double) * pixels * 4); + test = babl_malloc (sizeof (double) * test_pixels * 4); - for (i = 0; i < pixels * 4; i++) + for (i = 0; i < test_pixels * 4; i++) test [i] = ((double) random () / RAND_MAX ) * 1.4 - 0.2; return test; @@ -258,21 +258,26 @@ babl_model_is_symmetric (Babl *babl) fish_to = babl_fish_reference (ref_fmt, fmt); fish_from = babl_fish_reference (fmt, ref_fmt); - original = babl_calloc (1,64/8 * babl->model.components * pixels); - clipped = babl_calloc (1,64/8 * 4 * pixels); - destination = babl_calloc (1,64/8 * babl->model.components * pixels); - transformed = babl_calloc (1,64/8 * 4 * pixels); + original = babl_calloc (1,64/8 * babl->model.components * test_pixels); + clipped = babl_calloc (1,64/8 * 4 * test_pixels); + destination = babl_calloc (1,64/8 * babl->model.components * test_pixels); + transformed = babl_calloc (1,64/8 * 4 * test_pixels); - babl_process (fish_to, test, original, pixels); - babl_process (fish_from, original, clipped, pixels); - babl_process (fish_to, clipped, destination, pixels); - babl_process (fish_from, destination, transformed, pixels); + babl_process (fish_to, test, original, test_pixels); + babl_process (fish_from, original, clipped, test_pixels); + babl_process (fish_to, clipped, destination, test_pixels); + babl_process (fish_from, destination, transformed, test_pixels); + + fish_to->fish.processings-=2; + fish_from->fish.processings-=2; + fish_to->fish.pixels-=test_pixels*2; + fish_from->fish.pixels -= test_pixels*2; { int i; int log=0; - for (i=0;i